package com.suyafei.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.suyafei.config.RabbitMQConfig;
import com.suyafei.enums.*;
import com.suyafei.exception.BizException;
import com.suyafei.feign.AddressFeignService;
import com.suyafei.feign.CouponFeignService;
import com.suyafei.feign.ProductFeignService;
import com.suyafei.interceptor.LoginIntercept;
import com.suyafei.mapper.ProductOrderItemMapper;
import com.suyafei.mapper.ProductOrderMapper;
import com.suyafei.model.LoginUser;
import com.suyafei.model.OrderMessage;
import com.suyafei.model.ProductOrderDO;
import com.suyafei.model.ProductOrderItemDO;
import com.suyafei.request.ConfirmOrderRequest;
import com.suyafei.request.LockCouponRecordRequest;
import com.suyafei.request.LockProductRequest;
import com.suyafei.request.OrderItemRequest;
import com.suyafei.service.ProductOrderService;
import com.suyafei.util.CommonUtil;
import com.suyafei.util.JsonData;
import com.suyafei.vo.CouponRecordVO;
import com.suyafei.vo.OrderItemVO;
import com.suyafei.vo.ProductOrderAddressVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: suyafei-1024-shop
 * @description
 * @author: luffy
 * @create: 2021-03-15 10:15
 */
@Service
@Slf4j
public class ProductOrderServiceImpl implements ProductOrderService {

    @Autowired
    private RabbitMQConfig rabbitMQConfig;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ProductOrderItemMapper productOrderItemMapper;
    @Autowired
    private CouponFeignService couponFeignService;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private AddressFeignService addressFeignService;


    /**
     * 定时关单
     *
     * @param orderMessage
     * @return
     */
    @Override
    public boolean closeProductOrder(OrderMessage orderMessage) {


        //TODO

        ProductOrderDO productOrderDO = productOrderMapper.selectOne(new QueryWrapper<ProductOrderDO>().eq("out_trade_no", orderMessage.getOutTradeNo()));

        if (productOrderDO == null) {
            //订单不存在
            log.warn("直接确认消息，订单不存在:{}", orderMessage);
            return true;
        }
        if (productOrderDO.getState().equalsIgnoreCase(ProductOrderStateEnum.PAY.name())) {
            //已经支付
            log.warn("直接确认消息，订单已经支付：{}", orderMessage);
            return true;
        }

        //向三方查询是否真的未支付 TODO


        String payResult = "";
        //结果为空，则未支付成功，本地取消订单
        if (StringUtils.isBlank(payResult)) {
            productOrderMapper.updateOrderPayState(productOrderDO.getOutTradeNo(), ProductOrderStateEnum.CANCEL.name(), ProductOrderStateEnum.NEW.name());

            log.info("结果为空，则未支付成功，本地取消订单{}", orderMessage);
            return true;
        }else {
            //支付成功，主动的把订单状态改成已经支付，造成改原因的情况可能是支付通道回调有问题
            log.warn("支付成功，主动的把订单状态改成已经支付，造成改原因的情况可能是支付通道回调有问题{}", orderMessage);
            productOrderMapper.updateOrderPayState(productOrderDO.getOutTradeNo(), ProductOrderStateEnum.PAY.name(), ProductOrderStateEnum.NEW.name());
            return true;
        }
    }

    @Override
    public String queryProductOrder(String outTradeNo) {
        ProductOrderDO productOrderDO = productOrderMapper.selectOne(new QueryWrapper<ProductOrderDO>().eq("out_trade_no",outTradeNo ));
        if (productOrderDO != null) {
            return productOrderDO.getState();
        }
        return "";
    }

    /**
     * * 防重提交
     * * 用户微服务-确认收货地址
     * * 商品微服务-获取最新购物项和价格
     * * 订单验价
     * * 优惠券微服务-获取优惠券
     * * 验证价格
     * * 锁定优惠券
     * * 锁定商品库存
     * * 创建订单对象
     * * 创建子订单对象
     * * 发送延迟消息-用于自动关单
     * * 创建支付信息-对接三方支付
     *
     * @param confirmOrderRequest
     * @return
     */
    @Override
    public JsonData confirmOrder(ConfirmOrderRequest confirmOrderRequest) {
        LoginUser loginUser = LoginIntercept.threadLocal.get();
        String outTradeNo = CommonUtil.getStringNumRandom(32);

        ProductOrderAddressVO addressVO = this.getUserAddress(confirmOrderRequest.getAddressId());
        log.info("收货地址信息：{}", addressVO);

        List<Long> productIdList = confirmOrderRequest.getProductIdList();

        JsonData cartItemData = productFeignService.confirmOrderCartItems(productIdList);

        List<OrderItemVO> orderItemList = cartItemData.getData(new TypeReference<>() {});

        if (orderItemList == null) {
            //购物车商品不存在
            throw new BizException(BizCodeEnum.ORDER_CONFIRM_CART_ITEM_NOT_EXIST);
        }
        //验证价格，减去商品优惠券
        this.checkPrice(orderItemList, confirmOrderRequest);

        //锁定优惠券
        this.lockCouponRecords(confirmOrderRequest, outTradeNo);

        //锁定库存
        this.lockProductStock(orderItemList, outTradeNo);

        //创建订单
        ProductOrderDO productOrderDO = this.saveProductOrder(outTradeNo, confirmOrderRequest, loginUser, addressVO);

        //创建订单项
        this.saveProductOrderItems(outTradeNo, productOrderDO.getId(), orderItemList);

        //发送延迟消息
        OrderMessage orderMessage = new OrderMessage();
        orderMessage.setOutTradeNo(outTradeNo);
        rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getOrderCloseDelayRoutingKey(), orderMessage);
        //创建支付

        return null;
    }

    private void saveProductOrderItems(String outTradeNo, Long orderId, List<OrderItemVO> orderItemList) {

        List<ProductOrderItemDO> productOrderItemDOList = orderItemList.stream().map(
                obj->{
                    ProductOrderItemDO itemDo = new ProductOrderItemDO();
                    itemDo.setBuyNum(obj.getBuyNum());
                    itemDo.setProductId(obj.getProductId());
                    itemDo.setProductImg(obj.getProductImg());
                    itemDo.setProductName(obj.getProductTitle());

                    itemDo.setOutTradeNo(outTradeNo);
                    itemDo.setCreateTime(new Date());
                    //总价
                    itemDo.setTotalAmount(obj.getTotalAmount());
                    //单价
                    itemDo.setAmount(obj.getAmount());
                    itemDo.setProductOrderId(orderId);

                    return itemDo;
                }
        ).collect(Collectors.toList());

        productOrderItemMapper.insertBatch(productOrderItemDOList);
    }

    /**
     * 创建订单
     * @param outTradeNo
     * @param confirmOrderRequest
     * @param loginUser
     * @param addressVO
     * @return
     */
    private ProductOrderDO saveProductOrder(String outTradeNo, ConfirmOrderRequest confirmOrderRequest, LoginUser loginUser, ProductOrderAddressVO addressVO) {
        ProductOrderDO productOrderDO = new ProductOrderDO();
        productOrderDO.setUserId(loginUser.getId());
        productOrderDO.setHeadImg(loginUser.getHeadImg());
        productOrderDO.setNickname(loginUser.getName());


        productOrderDO.setOutTradeNo(outTradeNo);
        productOrderDO.setCreateTime(new Date());
        productOrderDO.setDel(0);
        productOrderDO.setOrderType(ProductOrderTypeEnum.DAILY.name());

        //实际支付的价格
        productOrderDO.setPayAmount(confirmOrderRequest.getRealPayAmount());

        //总价，未使用优惠券
        productOrderDO.setTotalAmount(confirmOrderRequest.getTotalAmount());
        productOrderDO.setState(ProductOrderStateEnum.NEW.name());
        productOrderDO.setPayType(ProductOrderPayTypeEnum.valueOf(confirmOrderRequest.getPayType()).name());

        productOrderDO.setReceiverAddress(JSON.toJSONString(addressVO));

        productOrderMapper.insert(productOrderDO);

        return productOrderDO;

    }

    /**
     *  锁定购物项库存
     * @param orderItemList
     * @param outTradeNo
     */
    private void lockProductStock(List<OrderItemVO> orderItemList, String outTradeNo) {
        LockProductRequest lockProductRequest = new LockProductRequest();
        List<OrderItemRequest> orderItemRequestList = new ArrayList<>();
        for (OrderItemVO orderItemVO : orderItemList) {
            OrderItemRequest orderItemRequest = new OrderItemRequest();
            orderItemRequest.setProductId(orderItemVO.getProductId());
            orderItemRequest.setBuyNum(orderItemVO.getBuyNum());
            orderItemRequestList.add(orderItemRequest);

        }
        lockProductRequest.setOrderOutTradeNo(outTradeNo);
        lockProductRequest.setOrderItemList(orderItemRequestList);
        JsonData jsonData = productFeignService.lockProducts(lockProductRequest);
        if (jsonData == null) {
            log.error("远程调用失败");
            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }
        if (jsonData.getCode() != 0) {
            log.error("库存锁定失败");
            throw new BizException(BizCodeEnum.ORDER_CONFIRM_ADD_STOCK_TASK_FAIL);
        }
    }

    /**
     * 锁定优惠券记录
     * @param confirmOrderRequest
     * @param outTradeNo
     */
    private void lockCouponRecords(ConfirmOrderRequest confirmOrderRequest, String outTradeNo) {
        Long couponRecordId = confirmOrderRequest.getCouponRecordId();
        if (couponRecordId > 0) {
            List<Long> couponIds = new ArrayList<>();
            LockCouponRecordRequest lockCouponRecordRequest = new LockCouponRecordRequest();
            couponIds.add(couponRecordId);
            lockCouponRecordRequest.setLockCouponRecordIds(couponIds);
            lockCouponRecordRequest.setOrderOutTradeNo(outTradeNo);

            JsonData jsonData = couponFeignService.lockCouponRecords(lockCouponRecordRequest);
            if (jsonData == null) {
                log.error("远程调用失败");
                throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
            }
            if (jsonData.getCode() !=  0) {
                log.error("优惠券锁定失败");
                throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
            }
        }
    }

    /**
     * 检查价格
     * @param orderItemList
     * @param confirmOrderRequest
     */
    private void checkPrice(List<OrderItemVO> orderItemList, ConfirmOrderRequest confirmOrderRequest) {

        BigDecimal realPayPriceAmount = new BigDecimal("0");
        if (orderItemList != null) {
            for (OrderItemVO orderItem : orderItemList) {
                BigDecimal itemTotalAmount = orderItem.getTotalAmount();
                realPayPriceAmount = realPayPriceAmount.add(itemTotalAmount);
            }
        }
        //获取优惠券，潘丹是否可以使用
        CouponRecordVO couponRecordVO = getCartCouponRecord(confirmOrderRequest.getCouponRecordId());
        //计算购物车价格，是否满足优惠券条件
        if (couponRecordVO != null) {
            //计算是否满足满减
            if (realPayPriceAmount.compareTo(couponRecordVO.getConditionPrice()) < 0) {
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_COUPON_FAIL);
            }

            if (couponRecordVO.getPrice().compareTo(realPayPriceAmount) > 0) {
                realPayPriceAmount = BigDecimal.ZERO;
            }else {
                realPayPriceAmount = realPayPriceAmount.subtract(couponRecordVO.getPrice());
            }
        }
        if (realPayPriceAmount.compareTo(confirmOrderRequest.getRealPayAmount()) != 0) {
            log.error("定价检验失败");
            throw new BizException(BizCodeEnum.ORDER_CONFIRM_PRICE_FAIL);
        }

    }

    private CouponRecordVO getCartCouponRecord(Long couponRecordId) {
        if (couponRecordId == null || couponRecordId < 0) {
            return null;
        }
        JsonData jsonData = couponFeignService.getCouponRecordDetail(couponRecordId);

        if (jsonData.getCode() != 0) {
            log.error("获取优惠券失败，msg{}", jsonData);
            throw new BizException(BizCodeEnum.ORDER_CONFIRM_COUPON_FAIL);
        }
        if (jsonData.getCode() == 0) {
            CouponRecordVO couponRecordVO = jsonData.getData(new TypeReference<>() {
            });
            if (!couponAvailable(couponRecordVO)) {
                log.error("优惠券使用失败");
                throw new BizException(BizCodeEnum.COUPON_UNAVAILABLE);
            }
            return couponRecordVO;
        }
        return null;
    }

    private boolean couponAvailable(CouponRecordVO couponRecordVO) {
        if (couponRecordVO.getUseState().equalsIgnoreCase(CouponStateEnum.NEW.name())) {
            long currentTimestamp = CommonUtil.getCurrentTimestamp();
            long end = couponRecordVO.getEndTime().getTime();
            long start = couponRecordVO.getStartTime().getTime();
            if (currentTimestamp >= start && currentTimestamp <= end
            ) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取收货地址详情
     * @param addressId
     * @return
     */
    private ProductOrderAddressVO getUserAddress(Long addressId) {
        JsonData detail = addressFeignService.detail(addressId);

        if (detail == null) {
            log.error("JsonData为空远程调用失败");
            throw new BizException(BizCodeEnum.ADDRESS_NO_EXITS);
        }
        if (detail.getCode() != 0) {
            log.error("获取收货地址失败");
            throw new BizException(BizCodeEnum.ADDRESS_NO_EXITS);
        }

        ProductOrderAddressVO addressVO = detail.getData(new TypeReference<>() {});

        return addressVO;

    }
}
